﻿namespace Devonline.Core
{
    /// <summary>
    /// key 生成器的参数构造器
    /// key 的组成参照 SnowFlake 算法, 64 = 1 + 41 + 14? + 8?
    /// 41 位毫秒值可以表示时间范围大约 69 年, 剩余 22 位为序列号和机器码
    /// BenchmarkMachineCode    : 0xFF
    /// MachineCode             : 0x00
    /// </summary>
    public class SnowFlakeOptions
    {
        /// <summary>
        /// 初始化默认值
        /// </summary>
        public SnowFlakeOptions()
        {
            DataCenterCode = 0x00;
            MachineCode = 0x00;
        }

        /// <summary>
        /// 当前机器码, 最大 5 位二进制;
        /// 默认值 0x00; 即第 0 号机器节点;
        /// </summary>
        public int MachineCode { get; set; }
        /// <summary>
        /// 当前数据中心码, 最大 5 位二进制
        /// 默认值 0x00; 即第 0 号数据中心节点;
        /// </summary>
        public int DataCenterCode { get; set; }
    }

    /// <summary>
    /// 借助 SnowFlake 实现的从配置文件读取配置初始化主键生成器
    /// </summary>
    public class KeyGenerator
    {
        /// <summary>
        /// SnowFlake 实例
        /// </summary>
        private static readonly SnowFlake snowFlake;
        /// <summary>
        /// 读取的配置节点名称
        /// </summary>
        private const string SECTION_NAME = nameof(SnowFlake);
        /// <summary>
        /// 生成器参数
        /// </summary>
        private static readonly SnowFlakeOptions options = new();

        /// <summary>
        /// 计算配置生成器的值
        /// </summary>
        static KeyGenerator()
        {
            Configure();
            snowFlake = new SnowFlake(options.MachineCode, options.DataCenterCode);
        }
        /// <summary>
        /// 使用依赖注入方式在项目启动时注入生成器所需的参数值;
        /// 常规委托注入方式, 配置后不要修改;
        /// </summary>
        /// <param name="action">生成器的参数构造器委托</param>
        public static void Configure(Action<SnowFlakeOptions>? action = null)
        {
            action?.Invoke(options);
            if (options.MachineCode <= 0)
            {
                options.MachineCode = 0x00;
            }

            if (options.MachineCode >= 0x1F)
            {
                options.MachineCode = 0x1F;
            }

            if (options.DataCenterCode <= 0)
            {
                options.DataCenterCode = 0x00;
            }

            if (options.DataCenterCode >= 0x1F)
            {
                options.DataCenterCode = 0x1F;
            }
        }
        /// <summary>
        /// 获取最新的 key
        /// </summary>
        /// <returns></returns>
        public static long GetKey() => snowFlake.GetId();
        /// <summary>
        /// 获取对应类型的 key
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <returns></returns>
        public static TKey GetKey<TKey>() where TKey : IConvertible => (TKey)Convert.ChangeType(snowFlake.GetId(), typeof(TKey));
    }
}
